<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <script>

    // 不应该直接重写Function原型对象上的call方法
    Function.prototype.call = function (obj, ...args) {
      console.log('call()')

      // 执行当前调用call方法的函数
      // 在方法内部, 如何得到调用方法的对象?
      // this(...args)

      // 给obj添加一个指向当前函数的临时方法
      obj.tempFn = this
      // 通过obj调用, 得到返回结果
      const result = obj.tempFn(...args)
      // 删除这个方法
      delete obj.tempFn
      // 返回result
      return result
    }

    function call(fun, obj, ...args) {
      console.log('call()')
      // 给obj添加一个指向当前函数的临时方法
      obj.tempFn = fun
      // 通过obj调用, 得到返回结果
      const result = obj.tempFn(...args)
      // 删除这个方法
      delete obj.tempFn
      // 返回result
      return result
    }

    function apply(fun, obj, args) {
      console.log('apply()')
      // 给obj添加一个指向当前函数的临时方法
      obj.tempFn = fun
      // 通过obj调用, 得到返回结果
      const result = obj.tempFn(...args)
      // 删除这个方法
      delete obj.tempFn
      // 返回result
      return result
    }

    function bind(fun, obj, ...args) {
      // 返回新函数
      return function (...args2) {
        // 执行原函数fun, 且this是obj
        return call(fun, obj, ...args, ...args2)
      }
    }
    /* 打印输出对象时: 会输出对象的快照(对象当时的数据情况) */
  </script>

  <script>
    const obj = {m: 1}
    function fn(a, b) {
      console.log(this, a, b)
      return a + b
    }
    /* 
    call(): 立即调用当前函数, 并, 指定this为第一个参数对象
    */
    // console.log(fn.call(obj, 2, 3))
    // console.log(call(fn, obj, 2, 3))
    // console.log(apply(fn, obj, [2, 3]))
    /* 
    bind(): 返回一个新函数, 执行新函数内部就会自动调用原函数, 且原函数中的this为bind的第一个参数对象
    */
    // console.log(fn.bind(obj)(2, 3))
    // console.log(fn.bind(obj, 4)(2, 3))
    // console.log(fn.bind(obj, 4, 5)(2, 3))
    console.log(bind(fn, obj)(2, 3))
    console.log(bind(fn, obj, 4)(2, 3))
    console.log(bind(fn, obj, 4, 5)(2, 3))

  </script>
</body>
</html>